package com.baoyouqun.config;

import cn.dev33.satoken.stp.StpUtil;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.util.ContentCachingRequestWrapper;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

/**
 * 打印请求信息的过滤器（支持 Body 参数）
 */
public class RequestLoggingFilter implements Filter {

    private static final Logger logger = LoggerFactory.getLogger(RequestLoggingFilter.class);

    // 支持读取 body 的 Content-Type（可根据实际需求扩展）
    private static final List<String> SUPPORTED_CONTENT_TYPES = Arrays.asList(
            "application/json",
            "application/x-www-form-urlencoded",
            "text/plain"
    );

    // 需要过滤的敏感字段（如密码、token 等）
    private static final List<String> SENSITIVE_FIELDS = Arrays.asList("password", "token", "secret");

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        // 包装请求，支持重复读取 body
        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper((HttpServletRequest) servletRequest);

        // 继续执行过滤器链（先让后续组件处理请求，确保 body 被缓存）
        filterChain.doFilter(wrappedRequest, servletResponse);

        // 提取请求关键信息
        String method = wrappedRequest.getMethod();
        String requestUrl = wrappedRequest.getRequestURL().toString();
        String queryString = wrappedRequest.getQueryString();
        String clientIp = wrappedRequest.getRemoteAddr();
        String userAgent = wrappedRequest.getHeader("User-Agent");
        String contentType = wrappedRequest.getContentType();

        // 获取 body 参数（仅处理支持的 Content-Type）
        String requestBody = getRequestBody(wrappedRequest, contentType);

        // 获取用户 ID（示例：从请求头或其他地方获取，需根据实际认证逻辑修改）
        String userId = getUserId(wrappedRequest);

        // 拼接日志信息
        String logMsg = """
                请求日志: - 
                Method: %s, 
                URL: %s, 
                Query: %s, 
                Body: %s, 
                User ID: %s, 
                Client IP: %s, 
                Content-Type: %s, 
                User-Agent: %s
                """.formatted(
                method,
                requestUrl,
                (queryString != null ? queryString : "none"),
                requestBody,
                userId,
                clientIp,
                (contentType != null ? contentType : "none"),
                userAgent
        );
        logger.info(logMsg);
    }

    /**
     * 读取并处理请求 body（过滤敏感信息）
     */
    private String getRequestBody(ContentCachingRequestWrapper request, String contentType) {
        // 跳过不支持的 Content-Type（如文件上传 multipart/form-data）
        if (contentType == null || !isSupportedContentType(contentType)) {
            return "unsupported content type";
        }

        // 从缓存中获取 body 字节数组
        byte[] bodyBytes = request.getContentAsByteArray();
        if (bodyBytes.length == 0) {
            return "empty";
        }

        // 转换为字符串并过滤敏感字段
        String body = new String(bodyBytes, StandardCharsets.UTF_8);
        return maskSensitiveFields(body);
    }

    /**
     * 判断 Content-Type 是否支持读取 body
     */
    private boolean isSupportedContentType(String contentType) {
        return SUPPORTED_CONTENT_TYPES.stream()
                .anyMatch(type -> contentType.toLowerCase().startsWith(type));
    }

    /**
     * 过滤敏感字段（替换为 ***）
     */
    private String maskSensitiveFields(String body) {
        String maskedBody = body;
        for (String field : SENSITIVE_FIELDS) {
            // 简单处理 JSON 格式（如 "password":"123" → "password":"***"）
            maskedBody = maskedBody.replaceAll("\"" + field + "\":\"[^\"]*\"", "\"" + field + "\":\"***\"");
            // 处理表单格式（如 password=123 → password=***）
            maskedBody = maskedBody.replaceAll(field + "=[^&]*", field + "=***");
        }
        return maskedBody;
    }

    private String getUserId(HttpServletRequest request) {
        String userId = "未登录用户";
        if (StpUtil.isLogin()) {
            userId = StpUtil.getLoginIdAsString();
        }
        return userId;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }
}